package com.csii.activiti.server.core.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.csii.activiti.server.core.constant.ActDefaultColumnConstant;
import com.csii.activiti.server.core.constant.CommonConstant;
import com.csii.activiti.server.core.entity.ActManyCondition;
import com.csii.activiti.server.core.entity.db.ActCommonDataEntity;

import java.util.*;

public class FormJsonProcessUtils {

    private static final Map<String,Integer> ELEMENT_TYPE_AND_LENGTH = new HashMap<>();

    private static final Map<String,String> ELEMENT_TYPE_AND_DB_TYPE = new HashMap<>();

    private static final String DIVIDER = "divider";
    private static final String CARD = "card";
    private static final String TABS = "tabs";
    private static final String GRID = "grid";
    private static final String TABLE = "table";
    private static final String DATE_CALCULATE = "dateCalculate";
    private static final String LIST = "list";
    private static final String TYPE = "type";
    private static final String KEY = "key";
    private static final String LABEL = "label";
    private static final String COLUMNS = "columns";
    private static final String TRS = "trs";
    private static final String TDS = "tds";
    private static final String ID = "id";
    private static final String MODEL = "model";
    private static final String OPTIONS = "options";
    private static final String VALUE = "value";
    private static final String REIMBURSEMENT = "reimbursement";
    private static final String WORK_OVERTIME = "workOvertime";
    private static final String INDUCTION = "induction";
    private static final String DEPARTURE = "departure";
    private static final String REGULARIZATION = "regularization";
    private static final String BUSINESS_TRIP = "businessTrip";

    private static final String CUSTOM = "custom";
    private static final String TICKET = "ticket";
    private static final String BATCH = "batch";

    private static final String TEXTAREA = "textarea";
    private static final String DATE = "date";
    private static final String TIME = "time";


    static {
        //初始化长度
        ELEMENT_TYPE_AND_LENGTH.put("input",500);
        ELEMENT_TYPE_AND_LENGTH.put("number",20);
        ELEMENT_TYPE_AND_LENGTH.put("select",200);
        ELEMENT_TYPE_AND_LENGTH.put("checkbox",500);
        ELEMENT_TYPE_AND_LENGTH.put("radio",200);
        ELEMENT_TYPE_AND_LENGTH.put(TEXTAREA,null);
        ELEMENT_TYPE_AND_LENGTH.put(DATE,null);
        ELEMENT_TYPE_AND_LENGTH.put(TIME,null);
        ELEMENT_TYPE_AND_LENGTH.put("uploadFile",1000);
        ELEMENT_TYPE_AND_LENGTH.put("uploadImg",1000);
    }

    public static void initDBTypes(){
        //初始化类型 区分数据类型
        if (DataSourceUtils.isOracle()) {
            ELEMENT_TYPE_AND_DB_TYPE.put(TIME,"NVARCHAR2");
            ELEMENT_TYPE_AND_DB_TYPE.put(DATE,"DATE");
            ELEMENT_TYPE_AND_DB_TYPE.put(TEXTAREA,"NCLOB");
            ELEMENT_TYPE_AND_DB_TYPE.put(null,"NVARCHAR2");
        }else{
            ELEMENT_TYPE_AND_DB_TYPE.put(TIME,"time");
            ELEMENT_TYPE_AND_DB_TYPE.put(DATE,"datetime");
            ELEMENT_TYPE_AND_DB_TYPE.put(TEXTAREA,"text");
            ELEMENT_TYPE_AND_DB_TYPE.put(null,"varchar");
        }
    }

    public static List<ActCommonDataEntity> formJsonProcessToCommonData(JSONObject formJson){
        return formJsonProcessToCommonData(formJson,true);
    }

    public static List<ActCommonDataEntity> formJsonProcessToCommonData(JSONObject formJson,boolean isInitDefault){
        List<ActCommonDataEntity> resultData = new ArrayList<>();
        if (isInitDefault){
            initDefaultActCommonDataEntity(resultData);
        }
        resultData.addAll(recursion(formJson));
        //oracle 数据库处理
        if (DataSourceUtils.isOracle()){
            processUpperCase(resultData);
        }
        return resultData;
    }

    public static void processUpperCase(List<ActCommonDataEntity> list){
        for (ActCommonDataEntity actCommonDataEntity : list) {
            actCommonDataEntity.setColumnName(actCommonDataEntity.getColumnName().toUpperCase());
        }
    }

    private static List<ActCommonDataEntity> recursion(JSONObject formJson){
        List<ActCommonDataEntity> resultData = new ArrayList<>();
        formJson.getJSONArray(LIST).forEach(obj->{
            JSONObject item = (JSONObject) obj;
            String type = item.getString(TYPE);
            switch (type){
                case DIVIDER:
                    break;
                case CARD:
                    resultData.addAll(recursion(item));
                    break;
                case TABS:
                    item.getJSONArray(COLUMNS).forEach(col->{
                        resultData.addAll(recursion((JSONObject) col));
                    });
                    break;
                case GRID:
                    item.getJSONArray(COLUMNS).forEach(col->{
                        resultData.addAll(recursion((JSONObject) col));
                    });
                    break;
                case TABLE:
                    item.getJSONArray(TRS).forEach(tr->{
                        ((JSONObject) tr).getJSONArray(TDS).forEach(td->{
                            resultData.addAll(recursion((JSONObject) td));
                        });
                    });
                    break;
                case DATE_CALCULATE: case REIMBURSEMENT: case WORK_OVERTIME:
                    case INDUCTION: case DEPARTURE: case REGULARIZATION: case BUSINESS_TRIP:
                    processCustomControl(resultData,item);
                    break;
                case TICKET :
                    ActCommonDataEntity actCommonDataEntity = new ActCommonDataEntity();
                    String key = CommonConstant.PREFIX_FORM_DATA + item.getString(KEY);
                    actCommonDataEntity.setId(TICKET);
                    actCommonDataEntity.setColumnName(key);
                    actCommonDataEntity.setColumnRemark(item.getString(LABEL));
                    actCommonDataEntity.setElementType(TICKET);
                    actCommonDataEntity.setDbType("text");
                    actCommonDataEntity.setFormAttributeName(key);
                    resultData.add(actCommonDataEntity);
                    break;
                default:
                    if (type.startsWith(CUSTOM) || type.startsWith(BATCH)){
                        actCommonDataEntity = new ActCommonDataEntity();
                        key = item.getString(KEY);
                        actCommonDataEntity.setId(key);
                        actCommonDataEntity.setColumnName(CommonConstant.PREFIX_FORM_DATA + key);
                        actCommonDataEntity.setColumnRemark(item.getString(LABEL));
                        actCommonDataEntity.setElementType(type);
                        actCommonDataEntity.setDbType(ELEMENT_TYPE_AND_DB_TYPE.get(TEXTAREA));
                        actCommonDataEntity.setFormAttributeName(CommonConstant.PREFIX_FORM_DATA + key);
                        resultData.add(actCommonDataEntity);
                    }else{
                        String model = item.getString(MODEL);
                        if (model != null){
                            actCommonDataEntity = new ActCommonDataEntity();
                            actCommonDataEntity.setId(item.getString(KEY));
                            actCommonDataEntity.setColumnName(CommonConstant.PREFIX_FORM_DATA + model);
                            actCommonDataEntity.setColumnRemark(item.getString(LABEL));
                            actCommonDataEntity.setElementType(item.getString(TYPE));
                            Integer columnLength = ELEMENT_TYPE_AND_LENGTH.get(actCommonDataEntity.getElementType());
                            String dbType = ELEMENT_TYPE_AND_DB_TYPE.get(actCommonDataEntity.getElementType());
                            if (columnLength == null && dbType == null){
                                actCommonDataEntity.setColumnLength(500);
                            }else{
                                actCommonDataEntity.setColumnLength(columnLength);
                            }
                            actCommonDataEntity.setDbType(dbType == null ? ELEMENT_TYPE_AND_DB_TYPE.get(null) : dbType);
                            actCommonDataEntity.setFormAttributeName(CommonConstant.PREFIX_FORM_DATA +model);
                            resultData.add(actCommonDataEntity);
                        }
                    }
            }
        });
        return resultData;
    }

    private static void processCustomControl(List<ActCommonDataEntity> resultData,JSONObject item){
        item.getJSONArray(LIST).forEach(subObj->{
            JSONObject subItem = (JSONObject) subObj;
            String model = subItem.getString(MODEL);
            if (model != null){
                ActCommonDataEntity actCommonDataEntity = new ActCommonDataEntity();
                actCommonDataEntity.setId(subItem.getString(KEY));
                actCommonDataEntity.setColumnName(CommonConstant.PREFIX_FORM_DATA + model);
                actCommonDataEntity.setColumnRemark(subItem.getString(LABEL));
                actCommonDataEntity.setElementType(subItem.getString(TYPE));
                Integer columnLength = ELEMENT_TYPE_AND_LENGTH.get(actCommonDataEntity.getElementType());
                String dbType = ELEMENT_TYPE_AND_DB_TYPE.get(actCommonDataEntity.getElementType());
                if(columnLength == null && dbType == null){
                    actCommonDataEntity.setColumnLength(500);
                }else{
                    actCommonDataEntity.setColumnLength(columnLength);
                }
                actCommonDataEntity.setDbType(dbType == null ? ELEMENT_TYPE_AND_DB_TYPE.get(null) : dbType);
                actCommonDataEntity.setFormAttributeName(CommonConstant.PREFIX_FORM_DATA +model);
                resultData.add(actCommonDataEntity);
            }

        });
    }

    public static Map<String, ActManyCondition> toManyConditions(String manyConditionsJson) {
        return JSONObject.parseObject(manyConditionsJson,new TypeReference<HashMap<String, ActManyCondition>>(){});
    }

    public static String recursionManyConditionsResultString(JSONObject formJson){
        if (formJson == null){
            return null;
        }
        return JSONObject.toJSONString(recursionManyConditions(formJson));

    }
    public static Map<String, ActManyCondition> recursionManyConditions(JSONObject formJson){
        Map<String, ActManyCondition> resultData = new HashMap<>();
        formJson.getJSONArray(LIST).forEach(obj->{
            JSONObject item = (JSONObject) obj;
            String type = item.getString(TYPE);
            switch (type){
                case DIVIDER:
                    break;
                case CARD:
                    resultData.putAll(recursionManyConditions(item));
                    break;
                case TABS:
                    item.getJSONArray(COLUMNS).forEach(col->{
                        resultData.putAll(recursionManyConditions((JSONObject) col));
                    });
                    break;
                case GRID:
                    item.getJSONArray(COLUMNS).forEach(col->{
                        resultData.putAll(recursionManyConditions((JSONObject) col));
                    });
                    break;
                case TABLE:
                    item.getJSONArray(TRS).forEach(tr->{
                        ((JSONObject) tr).getJSONArray(TDS).forEach(td->{
                            resultData.putAll(recursionManyConditions((JSONObject) td));
                        });
                    });
                    break;
                case DATE_CALCULATE: case REIMBURSEMENT: case WORK_OVERTIME:
                case INDUCTION: case DEPARTURE: case REGULARIZATION: case BUSINESS_TRIP:
                    item.getJSONArray(LIST).forEach(subObj->{
                        JSONObject subItem = (JSONObject) subObj;
                        String model = subItem.getString(MODEL);
                        if (model != null){
                            ActManyCondition actManyCondition = new ActManyCondition();
                            actManyCondition.setType(subItem.getString(TYPE));
                            JSONObject optionJson = subItem.getJSONObject(OPTIONS);
                            if (optionJson != null){
                                JSONArray optionArray = optionJson.getJSONArray(OPTIONS);
                                if (optionArray != null){
                                    Map<String, String> itemMap = new HashMap<>();
                                    for (Object option : optionArray) {
                                        JSONObject itemOption = (JSONObject) option;
                                        itemMap.put(itemOption.getString(VALUE),itemOption.getString(LABEL));
                                    }
                                    actManyCondition.setValAndLabel(itemMap);
                                }
                            }
                            resultData.put(CommonConstant.PREFIX_FORM_DATA + model,actManyCondition);
                        }

                    });
                    break;
                default:
                    if (type.startsWith(CUSTOM) || type.startsWith(BATCH)){
                        item.getJSONArray(LIST).forEach(subObj->{
                            JSONObject subItem = (JSONObject) subObj;
                            String model = subItem.getString(MODEL);
                            if (model != null){
                                ActManyCondition actManyCondition = new ActManyCondition();
                                actManyCondition.setType(subItem.getString(TYPE));
                                JSONObject optionJson = subItem.getJSONObject(OPTIONS);
                                if (optionJson != null){
                                    JSONArray optionArray = optionJson.getJSONArray(OPTIONS);
                                    if (optionArray != null){
                                        Map<String, String> itemMap = new HashMap<>();
                                        for (Object option : optionArray) {
                                            JSONObject itemOption = (JSONObject) option;
                                            itemMap.put(itemOption.getString(VALUE),itemOption.getString(LABEL));
                                        }
                                        actManyCondition.setValAndLabel(itemMap);
                                    }
                                }
                                resultData.put(CommonConstant.PREFIX_FORM_DATA + model,actManyCondition);
                            }

                        });
                    }else{
                        String model = item.getString(MODEL);
                        if (model != null){
                            ActManyCondition actManyCondition = new ActManyCondition();
                            actManyCondition.setType(item.getString(TYPE));
                            JSONObject optionJson = item.getJSONObject(OPTIONS);
                            if (optionJson != null){
                                JSONArray optionArray = optionJson.getJSONArray(OPTIONS);
                                if (optionArray != null){
                                    Map<String, String> itemMap = new HashMap<>();
                                    for (Object option : optionArray) {
                                        JSONObject itemOption = (JSONObject) option;
                                        itemMap.put(itemOption.getString(VALUE),itemOption.getString(LABEL));
                                    }
                                    actManyCondition.setValAndLabel(itemMap);
                                }
                            }
                            resultData.put(CommonConstant.PREFIX_FORM_DATA + model,actManyCondition);
                        }
                    }
            }
        });
        return resultData;
    }


    private static void initDefaultActCommonDataEntity(List<ActCommonDataEntity> currentCommonDataList){
        currentCommonDataList.add(new ActCommonDataEntity(ActDefaultColumnConstant.INITIATOR,"流程发起人",ELEMENT_TYPE_AND_DB_TYPE.get(null),"input",200,ActDefaultColumnConstant.INITIATOR));
        currentCommonDataList.add(new ActCommonDataEntity(ActDefaultColumnConstant.STATUS,"审批状态",ELEMENT_TYPE_AND_DB_TYPE.get(null),"input",20,ActDefaultColumnConstant.STATUS));
        currentCommonDataList.add(new ActCommonDataEntity(ActDefaultColumnConstant.START_TIME,"提交时间",ELEMENT_TYPE_AND_DB_TYPE.get(DATE),"date",null,ActDefaultColumnConstant.START_TIME));
        currentCommonDataList.add(new ActCommonDataEntity(ActDefaultColumnConstant.END_TIME,"完成时间",ELEMENT_TYPE_AND_DB_TYPE.get(DATE),"date",null,ActDefaultColumnConstant.END_TIME));
    }

    public static void main(String[] args) {
        String formJson = "{\"list\":[{\"type\":\"dateCalculate\",\"label\":\"请假套件\",\"dynamic\":\"\",\"dynamicKey\":\"\",\"options\":{\"width\":\"100%\",\"defaultValue\":\"\",\"showTime\":true,\"disabled\":false,\"hidden\":false,\"clearable\":false,\"placeholder\":\"请选择\",\"range\":true,\"rangePlaceholder\":[\"开始时间\",\"结束时间\"],\"format\":\"YYYY-MM-DD HH\",\"workingStart\":\"09:00\",\"workingEnd\":\"18:00\",\"workBreak\":\"1\",\"options\":[]},\"list\":[{\"type\":\"select\",\"label\":\"请假类型\",\"options\":{\"width\":\"100%\",\"multiple\":false,\"disabled\":false,\"clearable\":false,\"hidden\":false,\"placeholder\":\"请选择\",\"dynamicKey\":\"\",\"dynamic\":false,\"options\":[{\"label\":\"年假\",\"value\":\"yearLeave\"},{\"label\":\"事假\",\"value\":\"personalLeave\"}],\"showSearch\":false},\"list\":[],\"model\":\"leaveType\",\"key\":\"leaveType\",\"help\":\"\",\"prefix\":\"\",\"suffix\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]},{\"type\":\"date\",\"label\":\"开始时间\",\"icon\":\"icon-time\",\"options\":{\"width\":\"100%\",\"defaultValue\":\"\",\"disabled\":false,\"hidden\":false,\"clearable\":false,\"placeholder\":\"请选择\",\"format\":\"HH:mm:ss\"},\"model\":\"leaveStart\",\"key\":\"leaveStart\",\"help\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]},{\"type\":\"date\",\"label\":\"结束时间\",\"icon\":\"icon-time\",\"options\":{\"width\":\"100%\",\"defaultValue\":\"\",\"disabled\":false,\"hidden\":false,\"clearable\":false,\"placeholder\":\"请选择\",\"format\":\"HH:mm:ss\"},\"model\":\"leaveEnd\",\"key\":\"leaveEnd\",\"help\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]},{\"type\":\"number\",\"label\":\"请假时长\",\"icon\":\"icon-number\",\"options\":{\"width\":\"100%\",\"defaultValue\":0,\"min\":null,\"max\":null,\"precision\":null,\"step\":1,\"hidden\":false,\"disabled\":false,\"placeholder\":\"请输入\"},\"model\":\"leaveTime\",\"key\":\"leaveTime\",\"help\":\"\",\"prefix\":\"\",\"suffix\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]}],\"model\":\"dateCalculate_1628848470895\",\"key\":\"dateCalculate_1628848470895\",\"help\":\"\",\"rules\":[{\"required\":false,\"message\":\"必填项\"}]}],\"config\":{\"layout\":\"horizontal\",\"labelCol\":{\"xs\":4,\"sm\":4,\"md\":4,\"lg\":4,\"xl\":4,\"xxl\":4},\"wrapperCol\":{\"xs\":18,\"sm\":18,\"md\":18,\"lg\":18,\"xl\":18,\"xxl\":18},\"hideRequiredMark\":false,\"customStyle\":\"\"}}";
        System.out.println(formJsonProcessToCommonData(JSONObject.parseObject(formJson)));
       // String s = "{\"list\":[{\"type\":\"dateCalculate\",\"label\":\"请假场景\",\"dynamic\":\"\",\"dynamicKey\":\"\",\"options\":{\"width\":\"100%\",\"defaultValue\":\"\",\"showTime\":true,\"disabled\":false,\"hidden\":false,\"clearable\":false,\"placeholder\":\"请选择\",\"range\":true,\"rangePlaceholder\":[\"开始时间\",\"结束时间\"],\"format\":\"YYYY-MM-DD HH:mm\",\"workingStart\":\"\",\"workingEnd\":\"\",\"workBreak\":\"\",\"options\":[]},\"list\":[{\"type\":\"select\",\"label\":\"请假类型\",\"options\":{\"width\":\"100%\",\"multiple\":false,\"disabled\":false,\"clearable\":false,\"hidden\":false,\"placeholder\":\"请选择\",\"dynamicKey\":\"\",\"dynamic\":false,\"options\":[{\"label\":\"年假\",\"value\":\"yearLeave\"},{\"label\":\"事假\",\"value\":\"personalLeave\"}],\"showSearch\":false},\"list\":[],\"model\":\"leaveType\",\"key\":\"leaveType\",\"help\":\"\",\"prefix\":\"\",\"suffix\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]},{\"type\":\"time\",\"label\":\"开始时间\",\"icon\":\"icon-time\",\"options\":{\"width\":\"100%\",\"defaultValue\":\"\",\"disabled\":false,\"hidden\":false,\"clearable\":false,\"placeholder\":\"请选择\",\"format\":\"HH:mm:ss\"},\"model\":\"leaveStart\",\"key\":\"leaveStart\",\"help\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]},{\"type\":\"time\",\"label\":\"结束时间\",\"icon\":\"icon-time\",\"options\":{\"width\":\"100%\",\"defaultValue\":\"\",\"disabled\":false,\"hidden\":false,\"clearable\":false,\"placeholder\":\"请选择\",\"format\":\"HH:mm:ss\"},\"model\":\"leaveEnd\",\"key\":\"leaveEnd\",\"help\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]},{\"type\":\"number\",\"label\":\"请假时长\",\"icon\":\"icon-number\",\"options\":{\"width\":\"100%\",\"defaultValue\":0,\"min\":null,\"max\":null,\"precision\":null,\"step\":1,\"hidden\":false,\"disabled\":false,\"placeholder\":\"请输入\"},\"model\":\"leaveTime\",\"key\":\"leaveTime\",\"help\":\"\",\"prefix\":\"\",\"suffix\":\"\",\"rules\":[{\"required\":true,\"message\":\"必填项\"}]}],\"model\":\"dateCalculate_1620627299303\",\"key\":\"dateCalculate_1620627299303\",\"help\":\"\",\"rules\":[{\"required\":false,\"message\":\"必填项\"}]}],\"config\":{\"layout\":\"horizontal\",\"labelCol\":{\"xs\":4,\"sm\":4,\"md\":4,\"lg\":4,\"xl\":4,\"xxl\":4},\"wrapperCol\":{\"xs\":18,\"sm\":18,\"md\":18,\"lg\":18,\"xl\":18,\"xxl\":18},\"hideRequiredMark\":false,\"customStyle\":\"\"}}";
        //System.out.println(formJsonProcessToCommonData(JSONObject.parseObject(s)));
    }
}
